/// ADC DMA 缓冲区
uint16_t adcBuffer[3];

/// TIM1触发ADC1采样，DMA1传输
/// !!! 使用 DMA 传输的情况下，在访问 EEPROM 时，必须关闭 DMA !!! 并最好关闭中断，否则可能因 FLash 时序问题导致 down 机 !!!
void ADC1_TIM1TRGO_DMA1_Init(uint32_t sampleFreq) {
	//
	// 配置要使用的 DMA 通道
	//
	/* Enable DMA1 clock */
	CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);

	/* Connect ADC to DMA channel 0 */
	SYSCFG_REMAPDMAChannelConfig(REMAP_DMA1Channel_ADC1ToChannel0);

	DMA_DeInit(DMA1_Channel0);
	DMA_Init(
		DMA1_Channel0,
		(uint32_t)adcBuffer, (uint16_t)&(ADC1->DRH), 3,
		DMA_DIR_PeripheralToMemory,
		DMA_Mode_Circular,
		DMA_MemoryIncMode_Inc,
		DMA_Priority_High,
		DMA_MemoryDataSize_HalfWord );

	/* Enable DMA1 channelx Transfer complete interrupt */
	DMA_ITConfig(DMA1_Channel0, DMA_ITx_TC, ENABLE);

	/* DMA Channelx enable */
	DMA_Cmd(DMA1_Channel0, ENABLE);

	/* DMA enable */
	DMA_GlobalCmd(ENABLE);

	//
	// 配置 ADC 设备和通道
	//
	// 启动 ADC1 外设时钟
	CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);

	// 初始化要采样的 GPIO 口
	GPIO_Init(ADC_INPUT1_GPORT, ADC_INPUT1_GPIN, GPIO_Mode_In_FL_No_IT);
	GPIO_Init(ADC_INPUT2_GPORT, ADC_INPUT2_GPIN, GPIO_Mode_In_FL_No_IT);
	GPIO_Init(ADC_INPUT3_GPORT, ADC_INPUT3_GPIN, GPIO_Mode_In_FL_No_IT);

	// 初始化 ADC 设备
	ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_2);
	ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_96Cycles);

	ADC_ChannelCmd(ADC1, ADC_INPUT1_CHANNEL, ENABLE);
	ADC_ChannelCmd(ADC1, ADC_INPUT2_CHANNEL, ENABLE);
	ADC_ChannelCmd(ADC1, ADC_INPUT3_CHANNEL, ENABLE);

	// 禁止斯密特触发器，省电？
	ADC_SchmittTriggerConfig(ADC1, ADC_INPUT1_CHANNEL, DISABLE);
	ADC_SchmittTriggerConfig(ADC1, ADC_INPUT2_CHANNEL, DISABLE);
	ADC_SchmittTriggerConfig(ADC1, ADC_INPUT3_CHANNEL, DISABLE);

	// 启用内部参考电压
	ADC_VrefintCmd(ENABLE);
	// Enable ADC1
	ADC_Cmd(ADC1, ENABLE);

	//
	// 配置 TIM1 用于 AD 采样触发
	//
	// STM8L15x 只能使用 TIM1(ADC_ExtEventSelection_Trigger2)/TIM2(ADC_ExtEventSelection_Trigger3) 进行 ADC 采样触发
	CLK_PeripheralClockConfig(CLK_Peripheral_TIM1 ,ENABLE);

	// 计算合适的时钟配置参数
	// 对于频率为 50Hz 的交流电，如果每个正弦波周期要采样 100 个点，那么采样频率为 50*100 = 5000 Hz
	uint16_t prescaler=1, period=1;
	getBestClockConfigAdvance(CLK_GetClockFreq(), sampleFreq, MAXU16, MAXU16, (uint16_t*)&prescaler, &period);

	TIM1_DeInit();
	TIM1_TimeBaseInit(prescaler, TIM1_CounterMode_Up, period, 1);
	TIM1_PrescalerConfig(prescaler, TIM1_PSCReloadMode_Immediate);
	TIM1_ARRPreloadConfig(ENABLE);

	// 时钟暂时关闭，等需要采样时再打开
	TIM1_Cmd(DISABLE);

	//
	// 配置 ADC、DMA、TIM1
	//
	// 设置 TIM1 输出触发信号
	// Master Mode selection: Update event
	TIM1_SelectOutputTrigger(TIM1_TRGOSource_Update);
	// 外部触发 ADC 采样有3种方法：
	// ADC_ExtEventSelection_Trigger1 --> PA6/PD0外部信号触发
	// ADC_ExtEventSelection_Trigger2 --> TIM1.TRGO
	// ADC_ExtEventSelection_Trigger3 --> TIM2.TRGO
	// 这里采用的是 TIM1.TRGO
	ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_Trigger2, ADC_ExtTRGSensitivity_Rising);
	// Enable ADC1 DMA requests
	ADC_DMACmd(ADC1, ENABLE);
}

/// TIM1触发ADC1采样，中断传输
void PCB_ADC_Init(uint32_t sampleFreq) {
	//
	// 配置 ADC 设备和通道
	//
	CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);

	GPIO_Init(ADC_INPUT1_GPORT, ADC_INPUT1_GPIN, GPIO_Mode_In_FL_No_IT);

	// 初始化 ADC 设备
	ADC_Init(ADC1, ADC_ConversionMode_Single, ADC_Resolution_12Bit, ADC_Prescaler_2);
	ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_96Cycles);

	ADC_ChannelCmd(ADC1, ADC_INPUT1_CHANNEL, ENABLE);

	// 禁止斯密特触发器，省电？
	ADC_SchmittTriggerConfig(ADC1, ADC_INPUT1_CHANNEL, DISABLE);

	// 启用内部参考电压
	ADC_VrefintCmd(ENABLE);
	// Enable ADC1
	ADC_Cmd(ADC1, ENABLE);

	//
	// 配置 TIM1 用于 AD 采样触发
	//
	// STM8L15x 只能使用 TIM1(ADC_ExtEventSelection_Trigger2)/TIM2(ADC_ExtEventSelection_Trigger3) 进行 ADC 采样触发
	CLK_PeripheralClockConfig(CLK_Peripheral_TIM1 ,ENABLE);

	// 计算合适的时钟配置参数
	// 对于频率为 50Hz 的交流电，如果每个正弦波周期要采样 100 个点，那么采样频率为 50*100 = 5000 Hz
	uint16_t prescaler=1, period=1;
	getBestClockConfigAdvance(CLK_GetClockFreq(), sampleFreq, MAXU16, MAXU16, (uint16_t*)&prescaler, &period);

	TIM1_DeInit();
	TIM1_TimeBaseInit(prescaler, TIM1_CounterMode_Up, period, 1);
	TIM1_PrescalerConfig(prescaler, TIM1_PSCReloadMode_Immediate);
	TIM1_ARRPreloadConfig(ENABLE);

	// 时钟暂时关闭，等需要采样时再打开
	TIM1_Cmd(DISABLE);

	//
	// 配置 ADC、DMA、TIM1
	//
	// 设置 TIM1 输出触发信号
	// Master Mode selection: Update event
	TIM1_SelectOutputTrigger(TIM1_TRGOSource_Update);
	// 外部触发 ADC 采样有3种方法：
	// ADC_ExtEventSelection_Trigger1 --> PA6/PD0外部信号触发
	// ADC_ExtEventSelection_Trigger2 --> TIM1.TRGO
	// ADC_ExtEventSelection_Trigger3 --> TIM2.TRGO
	// 这里采用的是 TIM1.TRGO
	ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_Trigger2, ADC_ExtTRGSensitivity_Rising);

	// 配置ADC模拟看门狗上下门限，在过零点触发中断
  	ADC_AnalogWatchdogConfig(ADC1, ADC_INPUT1_AW_CHANNEL, 50000, 1);

	// 使能 ADC1 EOC(转换完成)中断
	ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
}

/// 启动 ADC 采样
void PCB_ADC_Start(uint8_t enable) {
	// 开启时钟触发
	TIM1_Cmd((FunctionalState)enable);
}


/// ADC1连续采样，门限触发中断
void PCB_ADC_Init() {
	// 使能外设时钟
	CLK_PeripheralClockConfig(CLK_Peripheral_ADC1, ENABLE);
	// IO 口配置为浮空输入
	GPIO_Init(ADC_INPUT1_GPORT, ADC_INPUT1_GPIN, GPIO_Mode_In_FL_No_IT);

	// 初始化 ADC 设备
	ADC_Init(ADC1, ADC_ConversionMode_Continuous, ADC_Resolution_12Bit, ADC_Prescaler_2);
	ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_384Cycles);

	// 使能要采样的通道
	ADC_ChannelCmd(ADC1, ADC_INPUT1_CHANNEL, ENABLE);

	// 禁止斯密特触发器，省电？
	ADC_SchmittTriggerConfig(ADC1, ADC_INPUT1_CHANNEL, DISABLE);

	// 启用内部参考电压
	ADC_VrefintCmd(ENABLE);

	// 配置ADC模拟看门狗上下门限，在过零点触发中断
  	ADC_AnalogWatchdogConfig(ADC1, ADC_INPUT1_AW_CHANNEL, 4095, 1);
	// 使能 ADC1 EOC(转换完成)中断
	ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
}

/// 启动 ADC 采样
void PCB_ADC_Start(uint8_t enable) {
	if(enable) {
		// Enable ADC1
		ADC_Cmd(ADC1, ENABLE);
		// 开始转换
		ADC_SoftwareStartConv(ADC1);
	} else {
		// Disable ADC1
		ADC_Cmd(ADC1, DISABLE);
	}
}
